import pandas as pd
import numpy as np

"""
系数矩阵的形式:
      x1  x2  x3  x4  x5  b
x3     9   4   1   0   0  360
x4     3   10  0   1   0  300
x5     4   5   0   0   1  200
fun   60  120  0   0   0   0
①第四行是目标函数的系数；亦即各变量对应的检验数；第1~3行是约束条件的系数
②第六列是约束方程的常数项
③对于目标函数的更新我们同样采用矩阵的变换,所以fun对应的第一列表示的是目标函数的相反数
"""
import pandas as pd
import numpy as np
matrix = pd.DataFrame(
    data=np.array([
        [9, 4, 1, 0, 0, 360],
        [3, 10, 0, 1, 0, 300],
        [4, 5, 0, 0, 1, 200],
        [60, 120, 0, 0, 0, 0],
    ]),
    index=['x3', 'x4', 'x5','fun'],
    columns=[ 'x1', 'x2', 'x3', 'x4', 'x5','b']
)
i=1
print("第",i,"个单纯性表是:")
print(matrix)

# 判断检验数是否大于0
c = matrix.iloc[-1, 0:-1]
while c.max() > 0:
    c = matrix.iloc[-1, 0:-1]
    i=i+1
    # 选择入基的变量
    in_x = c.idxmax()  # 该函数运行的结果是x2,即入基变量
    in_x_v = c[in_x]  # 得到入基变量的系数
    # 选择出基变量,即要计算θ的值,并比较大小
    b = matrix.iloc[0:-1, -1] #[360 300 200]
    # 选择入基变量对应的列
    in_x_a = matrix.iloc[0:-1][in_x]  #[4 10 5]
    # 得到出基变量
    out_x = (b / in_x_a).idxmin()

    # 完成入基和出基的操作,即对矩阵做初等行变化
    matrix.loc[out_x, :] = matrix.loc[out_x, :] / matrix.loc[out_x][in_x] # 出基变量x4的一行进行除以10
    for idx in matrix.index:
        if idx != out_x:
            matrix.loc[idx, :] = matrix.loc[idx, :] - matrix.loc[out_x, :] * matrix.loc[idx, in_x]

    # 索引变换
    index = matrix.index.tolist()  # 得到所以行索引的值
    i = index.index(out_x)  # 得到出基变量的下标
    index[i] = in_x
    matrix.index = index
    print("第",i,"个单纯性表是:")
    print(matrix)

# 输出结果
print("最终的最优单纯性法是:")
print(matrix)
print("目标函数的值:", - matrix.iloc[-1, -1])

# 列的数量减去行的数量得到非基变量的数量,且非基变量一定是下标在前的变量
# 比如非基变量的个数为2,则非基变量一定是x1,x2
print("最优决策变量是:")
x_count = (matrix.shape[1] - 1) - (matrix.shape[0] - 1)
X = matrix.iloc[-1, :-1].index.tolist()[:x_count]
for xi in X:
    print(xi, "=", matrix.loc[xi, 'b'])
